// @File  : centent.instance.go.go
// @Author: JunLong.Liao&此处不应有BUG!
// @Date  : 2021/5/27
// @slogan: 又是不想写代码的一天，神兽保佑，代码无BUG！
//         ┏┓      ┏┓
//        ┏┛┻━━━━━━┛┻┓
//        ┃     ღ    ┃
//        ┃  ┳┛   ┗┳ ┃
//        ┃     ┻    ┃
//        ┗━┓      ┏━┛
//          ┃      ┗━━━┓
//          ┃ 神兽咆哮!  ┣┓
//          ┃         ┏┛
//          ┗┓┓┏━━━┳┓┏┛
//           ┃┫┫   ┃┫┫
//           ┗┻┛   ┗┻┛

package CloudStorage

import (
	"context"
	"errors"
	"fmt"
	"github.com/tencentyun/cos-go-sdk-v5"
	"mime/multipart"
	"net/http"
	"net/url"
	"time"
)

var ctx = context.Background()

// TencentOSS interface
type TencentOSS interface {
	UploadFile(file *multipart.FileHeader) (path, filename string, err error) // Upload File to Tencent COS
	DeleteFile(key string) error                                              // Delete Tencent COS File
	GetBucketList() (buckets []cos.Bucket, err error)                         // GET Local Region All Bucket
	GetBucketACL() (Acl []cos.ACLGrant, err error)                            // GET Bucket ACL List
	GetBucketAccelerate() (result *cos.BucketGetAccelerateResult, err error)  // GET Bucket Accelerate
	PutBucketAccelerate(status string) error                                  // PUT Bucket Accelerate
}

// TencentCOS config
type TencentCOS struct {
	client     *cos.Client // tencentyun COS client
	Bucket     string      `mapstructure:"bucket" json:"bucket" yaml:"bucket"`               // 桶名称
	Region     string      `mapstructure:"region" json:"region" yaml:"region"`               // 地区
	SecretID   string      `mapstructure:"secret-id" json:"secretID" yaml:"secret-id"`       // 密钥 id
	SecretKey  string      `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`    // 密钥key
	BaseURL    string      `mapstructure:"base-url" json:"baseURL" yaml:"base-url"`          // 地址
	PathPrefix string      `mapstructure:"path-prefix" json:"pathPrefix" yaml:"path-prefix"` // 路径前缀
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @function: NewTencentOSS
// @description: 实现COS接口
// @param: c TencentCOS 初始化COS接口参数
// @return: TencentOSS
func NewTencentOSS(c *TencentCOS) TencentOSS {
	c.BaseURL = "https://" + c.Bucket + ".cos." + c.Region + ".myqcloud.com"

	return &TencentCOS{
		Bucket:     c.Bucket,
		Region:     c.Region,
		SecretID:   c.SecretID,
		SecretKey:  c.SecretKey,
		BaseURL:    c.BaseURL,
		PathPrefix: c.PathPrefix,
		client:     c.NewClient(),
	}
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @object: *TencentCOS
// @function: UploadFile
// @description: 删除Bucket里面对应key的文件
// @param: file *multipart.FileHeader 文件流
// @return: path string 文件访问地址
// @return: filename string 文件名
// @return: err error
func (t *TencentCOS) UploadFile(file *multipart.FileHeader) (path, filename string, err error) {
	f, openError := file.Open()
	if openError != nil {
		return "", "", errors.New("function file.Open() Filed, err:" + openError.Error())
	}
	fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename)

	_, err = t.client.Object.Put(ctx, t.PathPrefix+"/"+fileKey, f, nil)
	if err != nil {
		return "", "", errors.New("upload file Filed, err:" + err.Error())
	}
	return t.BaseURL + "/" + t.PathPrefix + "/" + fileKey, fileKey, nil
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @object: *TencentCOS
// @function: DeleteFile
// @description: 删除Bucket里面对应key的文件
// @param: key string 文件名
// @return: error
func (t *TencentCOS) DeleteFile(key string) error {
	name := t.PathPrefix + "/" + key
	_, err := t.client.Object.Delete(ctx, name)
	if err != nil {
		return errors.New("function bucketManager.Delete() Filed, err:" + err.Error())
	}
	return nil
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @object: *TencentCOS
// @function: NewClient
// @description: 初始化COS链接
// @param: 必须先初始化TencentCOS传入对应的配置参数
// @return: *cos.Client COS链接
func (t *TencentCOS) NewClient() *cos.Client {
	urlStr, _ := url.Parse(t.BaseURL)
	baseURL := &cos.BaseURL{BucketURL: urlStr}
	client := cos.NewClient(baseURL, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  t.SecretID,
			SecretKey: t.SecretKey,
		},
	})
	return client
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @object: *TencentCOS
// @function: GetBucketList
// @description: 获取当前区域所有的bucket
// @return: buckets []cos.Bucket 获取到的bucket列表
// @return: err error
func (t *TencentCOS) GetBucketList() (buckets []cos.Bucket, err error) {
	result, _, err := t.client.Service.Get(ctx)
	if err != nil {
		return nil, err
	}

	return result.Buckets, nil
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @object: *TencentCOS
// @function: GetBucketACL
// @description: 获取ACL访问控制列表
// @return: Acl []cos.ACLGrant 获取到的ACL列表
// @return: err error
func (t *TencentCOS) GetBucketACL() (Acl []cos.ACLGrant, err error) {
	result, _, err := t.client.Bucket.GetACL(ctx)
	if err != nil {
		return nil, err
	}

	return result.AccessControlList, nil
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @object: *TencentCOS
// @function: GetBucketAccelerate
// @description: 获取存储桶的全球加速状态
// @return: result *cos.BucketGetAccelerateResult COS返回的内容
// @return: err error
func (t *TencentCOS) GetBucketAccelerate() (result *cos.BucketGetAccelerateResult, err error) {
	result, _, err = t.client.Bucket.GetAccelerate(ctx)
	if err != nil {
		return nil, err
	}
	return
}

// @author: [wulala](https://github.com/water-gulugulu)
// @author: [wulala](https://gitee.com/diunigedaxigua)
// @object: *TencentCOS
// @function: PutBucketAccelerate
// @description: 启用或者暂停存储桶的全球加速
// @param: status string 枚举值：Suspended、Enabled
// @return: err error
func (t *TencentCOS) PutBucketAccelerate(status string) error {
	option := &cos.BucketPutAccelerateOptions{
		Status: status,
	}
	_, err := t.client.Bucket.PutAccelerate(ctx, option)
	if err != nil {
		return err
	}
	return nil
}
